﻿using System.Collections.Generic;
using BattleFury.Lib.Bots;
using BattleFury.Lib.Collections;
using BattleFury.Lib.Network;
using BattleFury.Lib.Players;
using BattleFury.Lib.ServerPlayer;
using BattleFuryGameEngine;
using BattleFuryGameEngine.Events;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using TextureCollection = BattleFury.Lib.Collections.TextureCollection;
using BattleFury.Lib.Extensions;

namespace BattleFury.Data
{
    public static class RenderData
    {
        #region Game Data

        private static readonly BattleFuryGame _bfg = BattleFuryGame.Get();

        public static List<string> Errors = new List<string>();

        public static TextureCollection Textures = new TextureCollection();
        public static TilesetCollection Tilesets = new TilesetCollection();
        public static FontCollection Fonts = new FontCollection();

        public static PlayerCollection Players = new PlayerCollection();
        public static BotCollection Bots = new BotCollection();

        public static BattleFuryWorld World = new BattleFuryWorld();

        #endregion

        #region Map Data

        public static Vector2 TileSize = new Vector2(32, 32);
        public static float CameraSpeed = 8f;

        #endregion

        #region Config Data

        private static int newPlayerID = 0;

        public static ClientConfiguration Config { get; private set; }

        public static void SetConfig(ClientConfiguration config)
        {
            Config = config;
            _bfg.Start();
        }

        public static void LoadFromConfig(ContentManager content)
        {
            if (Config == null)
            {
                Errors.Add("Configuration failed to load.");
                Log.Append("Configuration failed to load.");
                return;
            }

            ClientConfiguration config = Config;
            Texture2D characterTexture = Textures.Add("Character001", content.Load<Texture2D>(".\\gfx\\Characters\\Character001"));
            _bfg.PlayerAdded += PlayerAdded;
            _bfg.PlayerPositionUpdate += PlayerPositionUpdate;
            _bfg.PlayerMovementUpdate += PlayerMovementUpdate;
            if (!config.IsSpectator)
            {
                newPlayerID++;
                Player player = new Player(newPlayerID);
                player.Texture = characterTexture;
                player.Size = new Vector2(32f, 32f);
                player.MovementChanged += GenericPlayerMovementChanged;
                Players.Add(newPlayerID, player);

                _bfg.AddPlayer(newPlayerID);
            }

            foreach (var botConfig in config.Bots)
            {
                newPlayerID++;

                Bot bot = BotLoader.Load(botConfig.Path, botConfig.FullName, newPlayerID);
                bot.MovementChanged += GenericPlayerMovementChanged;
                bot.GetVisiblePlayersHandler = GetVisiblePlayer;
                Bots.Add(newPlayerID, bot);


                _bfg.AddPlayer(newPlayerID);
            }
        }

        #endregion

        #region Events

        private static void PlayerMovementUpdate(object sender, PlayerAddedEventArgs e)
        {
            GenericPlayer gp;
            if (!GetGenericPlayer(e, out gp)) { return; }
            gp.CurrentMovement = e.CurrentMovement;
        }

        private static void PlayerPositionUpdate(object sender, PlayerAddedEventArgs e)
        {
            GenericPlayer gp;
            if (!GetGenericPlayer(e, out gp)) { return; }
            gp.Position = e.Position;
        }


        private static void PlayerAdded(object sender, PlayerAddedEventArgs e)
        {
            GenericPlayer gp;
            if (!GetGenericPlayer(e, out gp)) { return; }
            gp.Position = e.Position;
            gp.Size = e.Size;
        }

        private static void GenericPlayerMovementChanged(GenericPlayer player, MovementChangedEventArge e)
        {
            _bfg.Networking_ReceivePacket(e.MovementPacket);
        }

        private static List<GenericPlayer> GetVisiblePlayer(GenericPlayer currentPlayer)
        {
            int visibility = 500;
            List<GenericPlayer> l = new List<GenericPlayer>();
            for (int i = 0; i < Players.Count; i++)
            {
                if (Players[i].Id != currentPlayer.Id && Players[i].Position.Distance(currentPlayer.Position) <= visibility)
                    l.Add(Players[i]);
            }
            return l;
        }

        private static bool GetGenericPlayer(PlayerAddedEventArgs e, out GenericPlayer gp)
        {
            gp = null;
            if (Players.ContainsKey(e.PlayerId))
                gp = Players[e.PlayerId];
            else if (Bots.ContainsKey(e.PlayerId))
                gp = Bots[e.PlayerId];
            else
                return false;
            return true;
        }

        #endregion
    }
}